#ifndef WOLF_SPRITE_HPP
#define WOLF_SPRITE_HPP

#include "common.hpp"
#include "rect.hpp"

namespace wolf
{
class WOLF_DECLSPEC Engine;
/**
 * @brief Representa a animated image
 * @ingroup utilMod
 *
 * The animation is automaticly actualized each frame
 *  according the velocity. It can be copied and assigned freely because it uses
 *  the SDL_Surface's reference counting.
 *
 * The Sprite class depends on the Engine status to work, so you can not instanciate
 *  a sprite if there is not an instance of Engine.
 **/
class Sprite
{
public:
	/**
	 * @brief Creates a new sprite
	 *
	 * The given imageFile is divided in lines and columns. The number of columns is the
	 *  integer division between the image width and the given width. The same is occurs
	 *  to the number of lines. Each cell is an frame (i.e. a subimage of the animation).
	 *  The number of frames is the lines times the columns number.
	 *
	 * @param imageFile the path to image location. It can be any of the supported formats
	 *  of SDL_Image library.
	 * @param nCollumns The number of columns.
	 * @param nRows The number of rows.
	 * @throw SdlException if it can't load the imageFile.
	 **/
	Sprite(const char *imageFile, int nCollumns, int nRows);

	/**
	 * @brief Creates a new sprite
	 *
	 * The given imageFile is divided in lines and columns. The number of columns is the
	 *  integer division between the image width and the given width. The same is occurs
	 *  to the number of lines. Each cell is an frame (i.e. a subimage of the animation).
	 *  The number of frames is the lines times the columns number.
	 *
	 * @param image an not null surface
	 * @param nCollumns The number of columns.
	 * @param nRows The number of rows.
	 * @param own true whether the sprite should take the responsibility to free the surface.
	 * @throw SdlException if it can't load the imageFile.
	 */
	Sprite(SDL_Surface *image, int nCollumns, int nRows, bool own = false);

	/**
	 * @brief Creates a new sprite
	 *
	 * The given imageFile is divided in lines and columns. The number of columns is the
	 *  integer division between the image width and the given width. The same is occurs
	 *  to the number of lines. Each cell is an frame (i.e. a subimage of the animation).
	 *  The number of frames is the lines times the columns number.
	 *
	 * @param src a readable RWops
	 * @param nCollumns The number of columns.
	 * @param nRows The number of rows.
	 * @param freesrc it true, it takes responsibility to free the RWops.
	 * @param type a string containing the type, like "BMP", "GIF", "PNG", etc. If it is null, it will try auto detect.
	 */
	Sprite(SDL_RWops *src, int nCollumns, int nRows, bool freesrc, const char *type = NULL);

	/**
	 * @brief Copy Constructor
	 *
	 *
	 **/
	Sprite(const Sprite &other);

	/**
	 * @brief Destroys the sprite
	 *
	 * And frees the surface
	 **/
	~Sprite();

	/**
	 * @brief Copies an sprite
	 *
	 *
	 **/
	Sprite &operator =(const Sprite &other);

	/**
	 * @brief Gets the velocity
	 **/
	double getVelocity() const;

	/**
	 * @brief Sets the velocity
	 **/
	void setVelocity(double vel);

	/**
	 * @brief Gets the offset
	 **/
	unsigned getOffset() const;

	/**
	 * @brief sets the offset
	 **/
	void setOffset(unsigned value);

	/**
	 * @brief Returns the current index of the frame
	 *
	 *
	 **/
	Uint16 getFrame(void) const;

	/**
	 * Sets the index
	 * @param ind the new index.
	 */
	void setFrame(Uint16 ind);

	/**
	 * @brief Gets the current Rect of  the surface
	 *
	 *
	 **/
	inline Rect getRect(void) const
	{
		Sint16 index = this->getFrame();
		Sint16 line = index / nColumns;
		Sint16 collumn = index % nColumns;
		return Rect(Sint16(collumn * width), Sint16(line * height), width, height);
	}

	/**
	 * @brief Draw the sprite onto the dst sprite
	 *
	 * @param dst the destiny surface
	 * @param x the x-axis
	 * @param y the y-axis
	 **/
	void draw(SDL_Surface *dst, int x, int y);

	/**
	 * @brief Returns the image
	 *
	 * You can't free the returned surface, otherwise it will cause a
	 *  segmentation fault.
	 *
	 * @return The current image.
	 **/
	SDL_Surface* getImage(void);

	/**
	 * @brief Returns the width
	 *
	 *
	 **/
	Uint16 getWidth(void) const
	{
		return width;
	}

	/**
	 * @brief Returns the height
	 *
	 *
	 **/
	Uint16 getHeight(void) const
	{
		return height;
	}

	/**
	 * @brief Returns if the pixel is transparent
	 *
	 *
	 **/
	bool transparent(unsigned line, unsigned col) const;

	/**
	 * Returns the number of frames
	 * @return the number of frames.
	 */
	Uint16 getFrameCount();

private:
	Uint16 offset;
	double velocity;
	SDL_Surface *image;
	Uint16 frameCount, nColumns;
	Uint16 width, height;

	/**
	 * Used on copy constructor an assignment operator.
	 * @param other
	 */
	void rawCopy(const Sprite &other);

	/**
	 * Used on constructors
	 * @param src the surface
	 * @param nCols the number of columns
	 * @param nRows the number of rows
	 */
	void _init(Uint16 nCols, Uint16 nRows);
};
}

#endif // WOLF_SPRITE_HPP
